<?php declare(strict_types=1);
/**
 * @author      xianganyall <xianganyall@gmail.com>
 * @copyright   2023-2025 owner
 **/

namespace Srv\Libs;

use Exception;
use Smarty;
use Phar;
use Srv\Libs\Common\CommFile;
use Srv\Libs\Common\CommString;
use Srv\Libs\Common\CommValid;
use Srv\Libs\ConfModel\SmartyConf;
use Srv\Libs\Frame\Conf;
use Srv\Libs\Frame\Lang;
use Srv\Libs\Frame\Logs;
use Srv\Libs\Frame\ResponseMain;
use Srv\Libs\Frame\Route;
use Srv\Libs\Pools\Pool;
use Srv\Libs\Storage\SmartyCacheRedis;
use Srv\Libs\Tools\ShellPrint;
use Swoole\Timer;
use Swoole\WebSocket\Server;
use Throwable;

final class Boot
{
    private const DS                                = '/';              // 目录分割符
    private const PHP_FILE_EXT                      = '.php';           // php文件后缀
    private const FILE_NAME_CONF                    = 'Conf';           // 配置文件名[无后缀]
    private const DIR_NAME_SRV                      = 'Srv';            // Srv
    private const DIR_NAME_CONF                     = 'Conf';           // Conf
    private const DIR_NAME_COMPOSER                 = 'Composer';       // Composer
    private const DIR_NAME_APPS                     = 'Apps';           // Apps
    private const DIR_NAME_LIBS                     = 'Libs';           // Libs
    private const PHAR_PREFIX_PROTOCOL              = 'phar://';        // phar Prefix
    private static string $confName                 = '';               // Run Conf Name
    private static string $programPath              = '';               // Run Program Path
    private static string $rootPath                 = '';               // Root
    private static string $srvPath                  = '';               // Srv
    private static string $confPath                 = '';               // Conf
    private static string $composerPath             = '';               // Composer
    private static string $appsPath                 = '';               // Apps
    private static string $libsPath                 = '';               // Libs
    private static int $timerLoop                   = 0;                // 循环间隔定时器
    private static int $timerLoopTimeMill           = 5000;             // 循环间隔时长[毫秒]
    private static int $timerLoopFast               = 0;                // 快速-循环间隔定时器
    private static int $timerLoopFastTimeMill       = 1000;             // 快速-循环间隔时长[毫秒]
    private static ?Smarty $SmartyInstance          = null;             // Smarty Instance

    /**
     * @param string $confName
     * @return void
     * runService
     */
    public static function runService(string $confName = ''):void
    {
        try{
            self::conf($confName, true);
            $ProjectConf    = Conf::getProjectConf();
            $WebSocketConf  = Conf::getWebSocketConf();
            $pgIdNum        = 0;
            $pIdNum         = 0;
            $pIdStr         = '';
            if(CommFile::getContent($WebSocketConf->getPidFile(), $pIdStr) && strlen($pIdStr) > 0) $pIdNum = intval($pIdStr);
            if($pIdNum > 0) $pgIdNum = posix_getpgid($pIdNum);
            $cliArgvList    = Conf::getCliArgvList();
            if(isset($cliArgvList[0])) switch (trim($cliArgvList[0])){
                case 'reload':{
                    if($pgIdNum < 1) die('Server No Running.'."\n");
                    if(posix_kill($pIdNum, SIGUSR1)){
                        ShellPrint::printSuccessString("Reload All Workers Process ...\n");
                    }else{
                        ShellPrint::printFailedString("Reload All Workers Process ...\n");
                    }
                    return;
                }
                case 'reloadTask':{
                    if($pgIdNum < 1) die('Server No Running.'."\n");
                    if(posix_kill($pIdNum, SIGUSR2)){
                        ShellPrint::printSuccessString("Reload Task Workers Process ...\n");
                    }else{
                        ShellPrint::printFailedString("Reload Task Workers Process ...\n");
                    }
                    return;
                }
                case 'stop':{
                    if($pgIdNum < 1) die('Server No Running.'."\n");
                    if(posix_kill($pIdNum, SIGKILL)){
                        ShellPrint::printSuccessString("Stop Server Process ...\n");
                    }else{
                        ShellPrint::printFailedString("Stop Server Process ...\n");
                    }
                    return;
                }
                case 'restart':{
                    if($pgIdNum > 0){
                        if(posix_kill($pIdNum, SIGKILL)){
                            ShellPrint::printSuccessString("Stop Server Process ...\n");
                        }else{
                            ShellPrint::printFailedString("Stop Server Process ...\n");
                        }
                        sleep(1);
                    }
                    break;
                }
                default:{   // start
                }
            }
            ShellPrint::printSuccessString("Start Server Process ...\n");
            $listenPort     = $WebSocketConf->getListen();
            $listenHost     = $WebSocketConf->getHost();
            if($listenPort < 1 || $listenPort > 65535) die('Config Fail, Listen Port Err: '.$listenPort."\n");
            if($WebSocketConf->isDaemonIze()){  // 检查Listen
                $errorLevel = error_reporting();
                error_reporting(0);
                set_error_handler(function(int $errNo, string $errStr, string $errFile, int $errLine):void{}, E_ALL);
                $listenHost = CommValid::isIpv6($listenHost) ? '['.$listenHost.']' : $listenHost;
                $errno      = 0;
                $errStr     = '';
                $socket     = @stream_socket_server('tcp://'.$listenHost.':'.$listenPort, $errno, $errStr);
                if(!$socket) die('Config Fail, Listen Port Fail: '.$listenPort.', '.$errno.', '.$errStr."\n");
                @fclose($socket);
                error_reporting($errorLevel);
                restore_error_handler();
            }
            ResponseMain::init($WebSocketConf, $ProjectConf);
        }catch(Exception $Exception){
            die('Config Fail, '.$Exception->getMessage()."\n");
        }
    }

    /**
     * @param string $confName
     * @return void
     * runConf
     */
    public static function runConf(string $confName):void
    {
        try{
            self::conf($confName, false);
        }catch(Exception $Exception){
            die('Config Fail, '.$Exception->getMessage());
        }
    }

    /**
     * @param string $confName
     * @param bool $isService
     * @return void
     * @throws Exception
     * conf
     */
    private static function conf(string $confName, bool $isService):void
    {
        !defined('IS_PHAR') && define('IS_PHAR', strlen(Phar::running()) > 0);
        self::$confName                 = $confName;
        $cliArgvData                    = [];
        $argv                           = $GLOBALS['argv']??($_SERVER['argv']??[]);
        if(count($argv) > 0){
            foreach($argv as $argvKey => $argvVal){
                if($argvKey < 1){
                    self::$programPath  = $argvVal;
                    continue;
                }
                $argvVal                = trim($argvVal);
                if(strlen($argvVal) < 1) continue;
                if(preg_match("/^--([a-z\d_\-.]+)=(.*)$/i", $argvVal, $match)){
                    $name               = is_numeric($match[1]) ? intval($match[1]) : trim($match[1]);
                    $value              = trim($match[2]);
                    $cliArgvData[$name] = $value;
                }else{
                    $cliArgvData[]      = $argvVal;
                }
            }
        }
        unset($GLOBALS['argv'], $GLOBALS['argc'], $_SERVER['argv'], $_SERVER['argc']);
        $runFilePath                    = trim(strval($argv[0]??''));
        if(IS_PHAR){
            if(strlen($runFilePath) > 0 && substr($runFilePath, 0, 1) === self::DS && file_exists(self::PHAR_PREFIX_PROTOCOL.$runFilePath.self::DS.self::DIR_NAME_LIBS.self::DS.basename(__FILE__))){
                self::$rootPath         = dirname($runFilePath).self::DS;
                self::$srvPath          = self::PHAR_PREFIX_PROTOCOL.$runFilePath.self::DS;
            }else{
                self::$rootPath         = str_replace(self::PHAR_PREFIX_PROTOCOL, '', dirname(__DIR__, 2).self::DS);
                self::$srvPath          = dirname(__DIR__).self::DS;
            }
        }else{
            if(strlen($runFilePath) > 0 && substr($runFilePath, 0, 1) === self::DS && file_exists(dirname($runFilePath, 2).self::DS.self::DIR_NAME_LIBS.self::DS.basename(__FILE__))){
                self::$rootPath         = dirname($runFilePath, 3).self::DS;
            }else{
                self::$rootPath         = dirname(__DIR__, 2).self::DS;
            }
            self::$srvPath              = self::$rootPath.self::DIR_NAME_SRV.self::DS;
        }
        self::$confPath                 = self::$srvPath.self::DIR_NAME_CONF.self::DS;
        self::$composerPath             = self::$srvPath.self::DIR_NAME_COMPOSER.self::DS;
        self::$appsPath                 = self::$srvPath.self::DIR_NAME_APPS.self::DS;
        self::$libsPath                 = self::$srvPath.self::DIR_NAME_LIBS.self::DS;
        spl_autoload_register([__CLASS__,   'autoLoadHandler'], true, true);
        set_exception_handler([__CLASS__,   'exceptionHandler']);
        set_error_handler([__CLASS__,       'errorHandler'], E_ALL);
        $envFile                        = self::$confPath.self::FILE_NAME_CONF.(strlen(self::$confName) > 0 ? '.'.self::$confName : '').self::PHP_FILE_EXT;
        if(!file_exists($envFile)) throw new Exception('Conf File Not Found, ['.$envFile.']');
        if(!Conf::init($envFile)) throw new Exception('Conf Init FAIL, ['.$envFile.']');
        Conf::setCliArgvList($cliArgvData);
        if(!Logs::init(Conf::getLogsConf())) throw new Exception('Logs Init FAIL');
        if(!Lang::init(Conf::getLangConf())) throw new Exception('Lang Init FAIL');
        $PhpConf                        = Conf::getPhpConf();
        if(!CommValid::isVersion($PhpConf->getVersionMin())) throw new Exception('Php version ERR, ['.$PhpConf->getVersionMin().']');
        if(version_compare(PHP_VERSION, $PhpConf->getVersionMin(), '<')) throw new Exception('Php version FAIL, ['.$PhpConf->getVersionMin().']');
        if(strlen($PhpConf->getExtList()) > 0){
            $phpExtMustList             = [];
            foreach(explode(',', $PhpConf->getExtList()) as $extName){
                $extName                = trim($extName);
                if(strlen($extName) > 0) $phpExtMustList[] = strtolower($extName);
            }
            if(count($phpExtMustList) > 0){
                $extDiffList            = array_diff($phpExtMustList, array_map(function($extName){ return strtolower($extName);}, get_loaded_extensions()));
                if(count($extDiffList) > 0) throw new Exception('Php Extension Not Found, ['.implode(',', $extDiffList).']');
            }
        }
        if(strlen($PhpConf->getTimeZone()) < 1) throw new Exception('Php TimeZone ERR, ['.$PhpConf->getTimeZone().']');
        if(!date_default_timezone_set($PhpConf->getTimeZone())) throw new Exception('Php TimeZone FAIL, ['.$PhpConf->getTimeZone().']');
        if($PhpConf->getTimeLimit() < 0 || $PhpConf->getTimeLimit() > 86400) throw new Exception('Php TimeLimit ERR, ['.$PhpConf->getTimeLimit().']');
        if(!set_time_limit($PhpConf->getTimeLimit())) throw new Exception('Php TimeLimit FAIL, ['.$PhpConf->getTimeLimit().']');
        switch(strtoupper($PhpConf->getErrorLevel())){
            case 'NONE':   { error_reporting(0); break; }
            case 'NOTICE': { error_reporting(E_ALL & ~E_DEPRECATED); break; }
            case 'WARNING':{ error_reporting(E_ALL & ~E_DEPRECATED & ~E_NOTICE); break; }
            case 'ERROR':  { error_reporting(E_ALL & ~E_DEPRECATED & ~E_NOTICE & ~E_WARNING); break; }
            case 'ALL':    { error_reporting(E_ALL); break; }
            default:{ throw new Exception('Php errorLevel FAIL, NONE/NOTICE/WARNING/ERROR/ALL, ['.$PhpConf->getErrorLevel().']'); }
        }
        // 设置最大处理的小数位
        ini_set('precision',            '16');
        ini_set('serialize_precision',  '16');
        ini_set('expose_php',           'Off');
        ini_set('short_open_tag',       'Off');
        $WebSocketConf                  = Conf::getWebSocketConf();
        if(!$isService){
            $WebSocketConf->setChRootPath('');
            self::loadComposer();
            return;
        }
        if($PhpConf->isChRoot()){
            $chRootPath                 = '';
            $chRootPathCalc             = rtrim(self::$rootPath, self::DS);
            do{
                if(file_exists($chRootPathCalc.'/etc/hosts')){
                    $chRootPath         = $chRootPathCalc.self::DS;
                    break;
                }
                $chRootPathCalc         = dirname($chRootPathCalc);
                if(strlen($chRootPathCalc) <= 1) break;
            }while(true);
            if(strlen($chRootPath) < 1) throw new Exception('Php chRoot Path Empty');
            $WebSocketConf->setChRootPath($chRootPath);
        }else{
            $WebSocketConf->setChRootPath('');
            self::loadComposer();
        }
    }

    /**
     * @param Server $WebSocketServer
     * @return void
     * start
     */
    public static function start(Server $WebSocketServer):void
    {
        $WebSocketConf                  = Conf::getWebSocketConf();
        $chRootPath                     = $WebSocketConf->getChRootPath();
        $chRootPathLength               = strlen($chRootPath);
        if(posix_getuid() !== 0 && $chRootPathLength > 0){    // 非root身份且有chroot时
            ShellPrint::printErrorString('chRoot Fail, ['.$WebSocketConf->getChRootPath().'], please run as root'."\n");
            $WebSocketServer->shutdown();
        }
    }

    /**
     * @param Server $WebSocketServer
     * @param int $workId
     * @return void
     * startWorker
     */
    public static function startWorker(Server $WebSocketServer, int $workId):void
    {
        $WebSocketConf      = Conf::getWebSocketConf();
        $chRootPath         = $WebSocketConf->getChRootPath();
        if(strlen($chRootPath) > 0){
            if(!self::chRoot($chRootPath)){
                ShellPrint::printErrorString('chRoot Fail, ['.$chRootPath.'], please run as root'."\n");
                if($workId === 0) $WebSocketServer->shutdown();
                return;
            }
            self::loadComposer();
        }
        // 路由初始化
        try{
            Route::init(Conf::getResponseConf());
        }catch (Exception $Exception){
            ShellPrint::printErrorString('Route Init Fail, ['.$Exception->getMessage().']'."\n");
            $WebSocketServer->shutdown();
            return;
        }
        Pool::init();   // 初始化连接池[每个进程]
        // 初始化Smarty
        $SmartyConf                     = Conf::getSmartyConf();
        self::$SmartyInstance           = new Smarty();
        self::$SmartyInstance->setTemplateDir($SmartyConf->getTplPath())->setCompileDir($SmartyConf->getCplPath())->setConfigDir($SmartyConf->getConfPath())->setCacheDir($SmartyConf->getCachePath());
        self::$SmartyInstance->setLeftDelimiter($SmartyConf->getLeft());
        self::$SmartyInstance->setRightDelimiter($SmartyConf->getRight());
        self::$SmartyInstance->setUseSubDirs($SmartyConf->isSubPath());
        self::$SmartyInstance->setDebugging($SmartyConf->isDebug());
        self::$SmartyInstance->setCompileCheck($SmartyConf->isCheck());
        self::$SmartyInstance->setCaching($SmartyConf->getCacheTime() > 0);
        self::$SmartyInstance->setCacheLifetime($SmartyConf->getCacheTime());
        if(strlen($SmartyConf->getCacheGroupName()) > 0){
            $cacheType                  = CommString::getClassOnlyName(SmartyCacheRedis::class);
            self::$SmartyInstance->setCachingType($cacheType);
            self::$SmartyInstance->registerCacheResource($cacheType, new SmartyCacheRedis());
        }
        if(count($SmartyConf->getClass()) > 0) foreach ($SmartyConf->getClass() as $classNameTpl => $classNameSrc){
            if(class_exists($classNameSrc)) self::$SmartyInstance->registerClass($classNameTpl, $classNameSrc);
        }
        if(count($SmartyConf->getPlugin()) > 0) foreach ($SmartyConf->getPlugin() as $pluginType => $pluginName){
            switch($pluginType){
                case SmartyConf::PLUGIN_TYPE_MODIFIER:
                case SmartyConf::PLUGIN_TYPE_BLOCK: {
                    if(!class_exists($pluginName)) continue 2;
                    $methodList     = get_class_methods($pluginName);
                    if(count($methodList) > 0) foreach ($methodList as $methodName){
                        $callable   = [$pluginName, $methodName];
                        if(!is_callable($callable)) continue;
                        try{ self::$SmartyInstance->registerPlugin($pluginType, $methodName, $callable); }catch(Exception $Exception){ Logs::error('registerPlugin Class Fail, ['.$pluginName.', '.$methodName.'], '.$Exception->getMessage(), __LINE__, __FILE__); }
                    }
                    break;
                }
                case SmartyConf::PLUGIN_TYPE_FUNCTION: {
                    if(strlen($pluginName) > 0 && function_exists($pluginName)){
                        try{ self::$SmartyInstance->registerPlugin($pluginType, $pluginName, $pluginName); }catch(Exception $Exception){ Logs::error('registerPlugin Function Fail, ['.$pluginName.'], '.$Exception->getMessage(), __LINE__, __FILE__); }
                    }
                }
            }
        }
        // 定时器
        if(self::$timerLoopTimeMill > 0) self::$timerLoop = Timer::tick(self::$timerLoopTimeMill, function(){
            Logs::loopTimerFlush();
            Pool::loopTimerCheck();
        });
        if(self::$timerLoopFastTimeMill > 0) self::$timerLoopFast = Timer::tick(self::$timerLoopFastTimeMill, function()use($WebSocketServer){
            if($WebSocketServer->taskworker){   // Task进程
                ResponseMain::handleAckPush();  // 处理重发socks消息
            }
        });
    }

    /**
     * @param int $workId
     * @return void
     * destroy
     */
    public static function destroy(int $workId):void
    {
        unset($workId);
        Pool::destroy();            // 销毁连接池[每个进程]
        if(self::$timerLoopFast > 0) Timer::clear(self::$timerLoopFast);
        self::$timerLoopFast    = 0;
        if(self::$timerLoop > 0) Timer::clear(self::$timerLoop);
        self::$timerLoop        = 0;
    }

    /**
     * @param string $chRootPath
     * @return bool
     * chRoot
     */
    private static function chRoot(string $chRootPath):bool
    {
        if($chRootPath === self::DS) return true;
        $chRootPathLength       = strlen($chRootPath);
        if($chRootPathLength < 3 || substr($chRootPath, -1) !== self::DS || $chRootPath !== substr(self::$rootPath, 0, $chRootPathLength)){
            Logs::error('chRoot Fail, ['.$chRootPath.']', __LINE__, __FILE__);
            return false;
        }
        $cwdPath                = posix_getcwd();
        if(is_string($cwdPath) && substr($cwdPath, 0, $chRootPathLength) === $chRootPath){
            Logs::error('chRoot Fail, ['.$chRootPath.']', __LINE__, __FILE__);
            return false;
        }
        self::$rootPath         = substr(self::$rootPath, $chRootPathLength-1);
        if(self::isPharPrefixProtocol(self::$srvPath)){
            self::$srvPath      = self::PHAR_PREFIX_PROTOCOL.substr(str_replace(self::PHAR_PREFIX_PROTOCOL, '', self::$srvPath), $chRootPathLength-1);
        }else{
            self::$srvPath      = substr(self::$srvPath, $chRootPathLength-1);
        }
        self::$confPath         = self::$srvPath.self::DIR_NAME_CONF.self::DS;
        self::$composerPath     = self::$srvPath.self::DIR_NAME_COMPOSER.self::DS;
        self::$appsPath         = self::$srvPath.self::DIR_NAME_APPS.self::DS;
        self::$libsPath         = self::$srvPath.self::DIR_NAME_LIBS.self::DS;
        $envFile                = self::$confPath.self::FILE_NAME_CONF.(strlen(self::$confName) > 0 ? '.'.self::$confName : '').self::PHP_FILE_EXT;
        if(!file_exists($envFile)){
            Logs::error('Conf File Not Found, ['.$envFile.']', __LINE__, __FILE__);
            return false;
        }
        if(!Conf::init($envFile)){
            Logs::error('Conf Init FAIL, ['.$envFile.']', __LINE__, __FILE__);
            return false;
        }
        if(!Logs::init(Conf::getLogsConf())){
            Logs::error('Logs Init FAIL', __LINE__, __FILE__);
            return false;
        }
        if(!Lang::init(Conf::getLangConf())){
            Logs::error('Lang Init FAIL', __LINE__, __FILE__);
            return false;
        }
        return true;
    }

    /**
     * @return void
     * loadComposer
     */
    private static function loadComposer():void
    {
        $composerAutoLoadFile       = self::$composerPath.'vendor/autoload.php';
        if(file_exists($composerAutoLoadFile)) require_once $composerAutoLoadFile;
    }

    /**
     * @param string $path
     * @return bool
     * isPharPrefixProtocol
     */
    private static function isPharPrefixProtocol(string $path):bool
    {
        $pathLength = strlen($path);
        if($pathLength < 1) return false;
        $length     = strlen(self::PHAR_PREFIX_PROTOCOL);
        if($pathLength < $length) return false;
        return strtolower(substr($path, 0, $length)) === self::PHAR_PREFIX_PROTOCOL;
    }

    /**
     * @param int $errNo
     * @param string $errStr
     * @param string $errFile
     * @param int $errLine
     * @return void
     * errorHandler
     */
    public static function errorHandler(int $errNo, string $errStr, string $errFile, int $errLine):void
    {
         Logs::error($errNo.','.$errStr, $errLine, $errFile);
    }

    /**
     * @param Throwable $exception
     * @return void
     * exceptionHandler
     */
    public static function exceptionHandler(Throwable $exception):void
    {
        Logs::exception($exception->getMessage(), $exception->getLine(), $exception->getFile());
    }

    /**
     * @param string $className
     * @return bool
     * autoLoadHandler
     */
    public static function autoLoadHandler(string $className):bool
    {
        $classFilePath      = self::getClassFilePath($className);
        if(strlen($classFilePath) < 5 || !file_exists($classFilePath)) return false;
        include_once $classFilePath;
        return class_exists($className, false);
    }

    /**
     * @param string $className
     * @return string
     * getClassFilePath
     */
    public static function getClassFilePath(string $className):string
    {
        $classNameNew   = str_replace('\\', self::DS, $className);
        list($classNamePrefix, $classNameOther)  = explode(self::DS, $classNameNew, 2);
        if($classNamePrefix === self::DIR_NAME_SRV){    // Srv 开头
            return self::getSrvPath().$classNameOther.self::PHP_FILE_EXT;
        }else{
            return self::getRootPath().$classNameNew.self::PHP_FILE_EXT;
        }
    }

    /**
     * @param string $filePath
     * @return string
     * getFilePathClassName
     */
    public static function getFilePathClassName(string $filePath):string
    {
        $rootPath           = self::getRootPath();
        if(self::isPharPrefixProtocol($filePath)) $filePath = str_replace(self::getSrvPath(), $rootPath.self::DIR_NAME_SRV.self::DS, $filePath);
        $rootPathLength     = strlen($rootPath);
        $filePathLength     = strlen($filePath);
        $fileExtDotLength   = strlen(self::PHP_FILE_EXT);
        if($filePathLength < $rootPathLength+1+$fileExtDotLength || substr($filePath, 0, $rootPathLength) !== $rootPath || substr($filePath, $fileExtDotLength*-1) !== self::PHP_FILE_EXT) return '';
        return str_replace('/', '\\', substr($filePath, $rootPathLength, $fileExtDotLength*-1));
    }

    /**
     * @return Smarty
     * getSmartyInstance
     */
    public static function getSmartyInstance():Smarty
    {
        return self::$SmartyInstance;
    }

    /**
     * @return string
     * getProgramPath
     */
    public static function getProgramPath():string
    {
        return self::$programPath;
    }

    /**
     * @return string
     * getRootPath
     */
    public static function getRootPath():string
    {
        return self::$rootPath;
    }

    /**
     * @return string
     * getSrvPath
     */
    public static function getSrvPath():string
    {
        return self::$srvPath;
    }

    /**
     * @return string
     * getAppsPath
     */
    public static function getAppsPath():string
    {
        return self::$appsPath;
    }

    /**
     * @return string
     * getComposerPath
     */
    public static function getComposerPath():string
    {
        return self::$composerPath;
    }

    /**
     * @return string
     * getConfPath
     */
    public static function getConfPath():string
    {
        return self::$confPath;
    }

    /**
     * @return string
     * getLibsPath
     */
    public static function getLibsPath():string
    {
        return self::$libsPath;
    }

    /**
     * @return string
     * getDataPath
     */
    public static function getDataPath():string
    {
        return Conf::getProjectConf()->getDataPath();
    }

    /**
     * @return string
     * getLogsPath
     */
    public static function getLogsPath():string
    {
        return Conf::getProjectConf()->getLogPath();
    }

    /**
     * @return string
     * getTmpPath
     */
    public static function getTmpPath():string
    {
        return Conf::getProjectConf()->getTmpPath();
    }

    /**
     * @return bool
     * isRelease
     */
    public static function isRelease():bool
    {
        return Conf::getProjectConf()->isRelease();
    }
}